import { flatten } from 'lodash-es';
import {
  UserImportsTemplateArgs,
  createImportMap,
  importPath,
  sortedImportKeys,
} from './shared.js';

export function userImportsLazyTemplate({
  globalImports,
  modulePaths: { fixturePaths, decoratorPaths },
  rendererConfig,
  rootDir,
  relativeToDir,
  typeScript,
}: UserImportsTemplateArgs) {
  function ext(filePath: string) {
    // Add compat with projects where allowImportingTsExtensions isn't enabled
    return typeScript ? filePath.replace(/\.tsx?$/, '') : filePath;
  }

  function ts(annotation: string) {
    return typeScript ? annotation : '';
  }

  const globalImportItems = globalImports.map(
    p => `import '${ext(importPath(p, relativeToDir))}';`
  );

  const fixtures = createImportMap(fixturePaths, rootDir, relativeToDir);
  const fixtureKeys = sortedImportKeys(fixtures);
  const fixtureItems = fixtureKeys.map(
    k => `  '${k}': { getModule: () => import('${ext(fixtures[k])}') }`
  );

  const decorators = createImportMap(decoratorPaths, rootDir, relativeToDir);
  const decoratorKeys = sortedImportKeys(decorators);
  const decoratorItems = decoratorKeys.map(
    k => `  '${k}': { getModule: () => import('${ext(decorators[k])}') }`
  );

  const rendererConfigStr = JSON.stringify(rendererConfig, null, 2);

  let importGroups = [globalImportItems];
  if (typeScript) {
    importGroups.unshift([
      `import type { RendererConfig, UserModuleWrappers } from 'react-cosmos-core';`,
    ]);
  }

  return `
// NOTE: This file is auto-generated by React Cosmos.
// It imports all fixture and decorator modules, making them available to the
// React Cosmos renderer along with the renderer config.
${importsStr(importGroups)}
export const rendererConfig${ts(': RendererConfig')} = ${rendererConfigStr};

const fixtures = {${objBody(fixtureItems)}};

const decorators = {${objBody(decoratorItems)}};

export const moduleWrappers${ts(': UserModuleWrappers')} = {
  lazy: true,
  fixtures,
  decorators
};
`.trimStart();
}

function importsStr(items: string[][]) {
  if (flatten(items).length === 0) {
    return '';
  }

  const str = items
    .filter(rows => rows.length > 0)
    .map(rows => rows.join('\n'))
    .join('\n\n');

  return `\n${str}\n`;
}

function objBody(items: string[]) {
  return items.length > 0 ? `\n${items.join(`,\n`)}\n` : '';
}
